/** @format */

import fs from 'fs-extra'
import path from 'path'
import XLSX from 'xlsx'
import astToObj from './astToObj.js'
import {
  scriptEnHandle,
  strToObj,
  loadChildModule,
  rmDir,
  isFileExisted,
} from './utils.js'

import globalConfig from './config.js' //配置项

function resolvePath() {
  Object.keys(globalConfig.entry)?.forEach?.((key) => {
    if (typeof globalConfig.entry[key] === 'string') {
      const obj = {
        path: path.resolve(globalConfig.entry[key]),
        i18nSource: path.resolve(`${globalConfig.langSourcePath}/${key}.js`),
        module: loadChildModule(path.resolve(globalConfig.entry[key])),
        prefix: `${globalConfig.rootModuleName}-${key}_`,
        prefixCode: `${globalConfig.rootModuleName}.${key}`,
      }
      Object.assign(globalConfig.entry[key], obj)
    } else {
      const _path = path.resolve(globalConfig.entry[key]?.path)
      globalConfig.entry[key].path = _path
      globalConfig.entry[key].i18nSource = path.resolve(
        globalConfig.entry[key].i18nSource
      )
      globalConfig.entry[key].module = loadChildModule(
        _path,
        globalConfig.entry[key]
      )
    }
  })
  globalConfig.output = path.resolve(globalConfig.output)
}

const deconstruction = () => {
  function saveJsword(file, list) {
    // js
    if (!globalConfig.saveReplaceObj[file]) {
      globalConfig.saveReplaceObj[file] = {
        jsTextData: [],
      }
    }
    if (!globalConfig.saveReplaceObj[file]?.jsTextData) {
      globalConfig.saveReplaceObj[file].jsTextData = [...list]
    } else {
      globalConfig.saveReplaceObj[file].jsTextData = [
        ...globalConfig.saveReplaceObj[file]?.jsTextData,
        ...list,
      ]
    }
  }
  function handle(module) {
    let _moduleData = []
    globalConfig.entry[module]?.module?.forEach((file) => {
      //记录单个ast对象
      let astData = null
      //记录单个文件word
      let curFileData = []
      const data = fs.readFileSync(file, 'utf8')
      const vueReg = /\.vue$/gi
      const jsReg = /<script\s*(setup)*\s*\>[\s\S]*?<\/script>/gi
      // sfc template && js
      if (vueReg.test(file)) {
        const { obj, arr } = astToObj(data, globalConfig, file)
        astData = obj
        // 收集vue script
        data.replace(jsReg, function (word) {
          const list = scriptEnHandle(word, globalConfig, file)
          saveJsword(file, list)
          curFileData = [...arr, ...list]
        })
      } else {
        const list = scriptEnHandle(data, globalConfig, file)
        saveJsword(file, list)
        curFileData = [...list]
      }
      _moduleData = [..._moduleData, ...curFileData]
      if (curFileData?.length > 0) {
        sourceModules[module][file] = curFileData
      }
      if (astData?.length > 0) {
        astModules[module][file] = astData
      }
    })
    return _moduleData
  }
  // 源文件
  const sourceModules = {}
  const dataModules = {}
  const astModules = {}
  Object.keys(globalConfig.entry)?.forEach((item) => {
    astModules[item] = {}
    sourceModules[item] = {}
    dataModules[item] = [...new Set(handle(item))]
  })
  return {
    sourceModules,
    dataModules,
    astModules,
  }
}
// 补0
function padToFourDigits(num) {
  return `${num}`.padStart(4, '0')
}
function writeModuleFile(moduleName, moduleContent, moduleConfigData) {
  if (!fs.existsSync(globalConfig.output)) {
    fs.mkdirSync(globalConfig.output)
  }
  const moduleObj = globalConfig.entry[moduleName]
  const filepath = moduleObj.i18nSource
  const bool = isFileExisted(filepath)
  let prevIdx = 0
  let dataObj = {}
  let dataArr = []
  if (bool) {
    const data = fs.readFileSync(filepath, 'utf8')
    dataObj = strToObj(data)
    Object.keys(dataObj)?.forEach((key) => {
      dataArr.push(dataObj[key])
      const i = key.match(/\d+/g)?.pop()
      if (
        Number(i) &&
        Number(i) > prevIdx &&
        key.indexOf(moduleConfigData.prefix) !== -1
      ) {
        prevIdx = i
      }
    })
  }
  if (prevIdx > 0) {
    prevIdx++
  }
  const obj = {}
  let idx = -1
  moduleContent?.forEach((item) => {
    // 已经存在就不重复记录
    if (dataArr.includes(item)) return
    idx++
    const key = moduleObj.prefix + padToFourDigits(idx + prevIdx)
    obj[key] = item
  })
  if (Object.keys(obj).length === 0) return
  const newobj = Object.assign(dataObj, obj)
  fs.writeFileSync(
    filepath,
    'export default ' +
      JSON.stringify(newobj, null, 2) +
      ';' +
      '\n' +
      `// 本次index从${prevIdx}开始`,
    { flag: 'w+' }
  )
  return obj
}
function writeAst(moduleContent) {
  const dir = path.join(globalConfig.output, '/ast')
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir)
  }
  Object.keys(globalConfig.entry)?.forEach((item) => {
    const dirChild = path.join(dir, `/${item}`)
    if (!fs.existsSync(dirChild)) {
      fs.mkdirSync(dirChild)
    }
    Object.keys(moduleContent[item])?.forEach((file) => {
      const index = file.indexOf(item) + item.length
      let filename = file.substring(index)
      filename = filename.replace(/(\/|\.)/gi, '_')
      fs.writeFileSync(
        dirChild + `/${filename}.js`,
        JSON.stringify(moduleContent[item][file], null, 2),
        { flag: 'w+' }
      )
    })
  })
}
function writeSource(sourceModules) {
  const dir = path.join(globalConfig.output, '/resource')
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir)
  }
  Object.keys(globalConfig.entry)?.forEach((item) => {
    let str = ''
    Object.keys(sourceModules[item])?.forEach((file) => {
      const index = file.indexOf(item) + item.length
      let filename = file.substring(index)
      filename = filename.replace(/(\/|\.)/gi, '_')
      str += `// ${file}\nconst ${filename} = ${JSON.stringify(
        sourceModules[item][file],
        null,
        2
      )}\n`
    })
    fs.writeFileSync(path.join(dir, `/${item}_bundle.js`), str, {
      flag: 'w+',
    })
  })
}

function mergeUserConfig(config) {
  if (!config) return
  Object.keys(config)?.forEach((key) => {
    if (Object.prototype.hasOwnProperty.call(globalConfig, key)) {
      if (typeof config[key] === 'object' && config[key] !== null) {
        if (Array.isArray(globalConfig[key])) {
          // 通过set合并两个数组
          globalConfig[key] = [
            ...new Set([...globalConfig[key], ...config[key]]),
          ]
        } else {
          globalConfig[key] = {
            ...globalConfig[key],
            ...config[key],
          }
        }
      } else {
        globalConfig[key] = config[key]
      }
    }
  })
}

async function createWorksheet(dataModules, config) {
  const languages = config.languages
  // 创建工作表数据
  const headers = ['key', ...languages]
  const rows = []

  for (const mod in dataModules) {
    const modData = dataModules[mod]
    if (modData) {
      for (const key in modData) {
        const row = [key]
        row.push(modData[key] || '')
        rows.push(row)
      }
    }
  }

  if(rows.length === 0) {
    console.log('没有增加需要翻译的词条数据')
    return
  }

  // 创建工作表
  const workbook = XLSX.utils.book_new()
  const worksheetData = [headers, ...rows]
  const worksheet = XLSX.utils.aoa_to_sheet(worksheetData)
  XLSX.utils.book_append_sheet(workbook, worksheet, 'i18n')

  await fs.ensureDir(config.xlsxDir)
  // 日期格式化取得分
  const fileName = `i18n_collect_${new Date().toLocaleDateString().replace(/\//g, '')}.xlsx`
  const outputPath = path.join(config.xlsxDir, fileName)
  XLSX.writeFile(workbook, outputPath)

  console.log(`生成文件: ${outputPath}`)
}

export async function start(config) {
  try {
    mergeUserConfig(config.collect)

    resolvePath()
    const { sourceModules, dataModules, astModules } = deconstruction()
    if (fs.existsSync(globalConfig.output)) {
      rmDir(globalConfig.output)
    }
    const filterDataModules = {}
    Object.keys(dataModules)?.forEach((moduleName) => {
      filterDataModules[moduleName] = writeModuleFile(
        moduleName,
        dataModules[moduleName],
        globalConfig.entry[moduleName]
      )
    })
    if (globalConfig.mode === 'dev') {
      writeAst(astModules)
    }
    writeSource(sourceModules)
    // 用户处理
    const pt = path.resolve(
      path.__dirname,
      `${globalConfig.output}/user_handle.js`
    )
    fs.writeFileSync(pt, JSON.stringify(globalConfig.userHandle, null, 2), {
      flag: 'w+',
    })

    if (globalConfig.isCreateExcel) {
      await createWorksheet(filterDataModules, config)
    }

    console.log('程序收集完成...')
    // });
  } catch (e) {
    throw new Error(e)
  }
}

// 替换时候使用
export function startRep(config) {
  try {
    return new Promise((resolve) => {
      mergeUserConfig(config)
      resolvePath()
      const { astModules } = deconstruction()
      if (astModules) {
        resolve(globalConfig)
      }
    })
  } catch (e) {
    throw new Error(e)
  }
}
